﻿using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.RegularExpressions;

using YourLastOptionsDialog.Controls;

namespace YourLastOptionsDialog.ViewModels.Options
{
    /// <summary>
    /// A validator for integral types.
    /// </summary>
    public class IntegralValidator : IValidator
    {
        private readonly Type _type;

        private readonly long _minimum;

        private readonly long _maximum;

        /// <summary>
        /// Gets or sets the validation error message.
        /// </summary>
        public string ValidationErrorMessage
        {
            get;
            set;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="IntegralValidator"/> class.
        /// </summary>
        /// <param name="type">The actual type of the integral.</param>
        /// <param name="minimum">The allowed minimum used for validation.</param>
        /// <param name="maximum">The allowed maximum used for validation.</param>
        public IntegralValidator(Type type, long minimum, long maximum)
        {
            _type = type;
            _minimum = minimum;
            _maximum = maximum;
        }

        #region Implementation of IValidator

        /// <summary>
        /// Validates the specified input and returns a <see cref="ValidationResult"/> with the outcome of the validation.
        /// </summary>
        /// <param name="input">The input value to validate.</param>
        /// <returns>
        /// The result of the validation.
        /// </returns>
        [SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "result", Justification = "Used for overflow check.")]
        public ValidationResult Validate(string input)
        {
            var regex = new Regex("^-*[0-9]*$");
            if (!regex.IsMatch(input))
            {
                return new ValidationResult(false, ValidationErrorMessage);
            }

            // try to convert
            try
            {
                // convert to the actual result (captures overflow errors etc.)
                var result = Convert.ChangeType(input, _type, CultureInfo.CurrentCulture);

                // check against min/max (for this, we convert to long)
                // Note: we have a problem with edge cases here. E.g. this does not allow values > Int64.MaxValue,
                // which may happen for values < UInt64.MaxValue. But we can live with that for now.
                var numericResult = (long)Convert.ChangeType(input, typeof(long), CultureInfo.CurrentCulture);
                if (numericResult < _minimum || numericResult > _maximum)
                {
                    return new ValidationResult(false, ValidationErrorMessage);
                }
            }
            catch (Exception)
            {
                return new ValidationResult(false, ValidationErrorMessage);
            }

            return ValidationResult.Success;
        }

        #endregion
    }
}